package com.tender.integration.websocket.interceptor;

import com.tender.constants.Constants;
import com.tender.constants.WebSocketConstants;
import com.tender.integration.websocket.WebSocketConfiguration;
import com.tender.utils.ApplicationContextUtil;
import com.tender.utils.LoginUser;
import com.tender.service.TokenService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;
import com.tender.enums.DeviceEnum;
import com.tender.exceptions.CommonException;
import com.tender.enums.ErrorTypeEnum;

import java.util.Map;

/**
 * @see WebSocketConfiguration
 */
@Slf4j
public class WebSocketInterceptor implements HandshakeInterceptor {

    private volatile TokenService tokenService;

    /**
     * 建立请求之前，可以用来做权限判断
     * 前端请求地址demo：
     * ws://10.220.5.226:8086/ws/msg?token=xxxxx&device=
     *
     * @param request    the current request
     * @param response   the current response
     * @param wsHandler  the target WebSocket handler
     * @param attributes the attributes from the HTTP handshake to associate with the WebSocket
     *                   session; the provided attributes are copied, the original map is not used.
     * @return
     * @throws Exception
     */
    @Override
    public boolean beforeHandshake(ServerHttpRequest request,
                                   ServerHttpResponse response,
                                   WebSocketHandler wsHandler,
                                   Map<String, Object> attributes) throws Exception {
        if (request instanceof ServletServerHttpRequest) {
            ServletServerHttpRequest servletServerHttpRequest = (ServletServerHttpRequest) request;
            // 模拟用户（通常利用JWT令牌解析用户信息）
            // 获取 ? 后面的参数 token
            String token = servletServerHttpRequest.getServletRequest().getParameter("token");
            String device = servletServerHttpRequest.getServletRequest().getParameter("device");
            if (StringUtils.isBlank(token)) {
                throw new CommonException(String.format(ErrorTypeEnum.DATA_NOT_EMPTY.getErrorMsgCn(), "token"),
                        ErrorTypeEnum.DATA_NOT_EMPTY.getCode());
            }
            if (StringUtils.isBlank(device)) {
                throw new CommonException(String.format(ErrorTypeEnum.DATA_NOT_EMPTY.getErrorMsgCn(), "设备类型"),
                        ErrorTypeEnum.DATA_NOT_EMPTY.getCode());
            }
            DeviceEnum deviceEnum = DeviceEnum.getEnum(device);
            if (null == deviceEnum) {
                throw new CommonException(ErrorTypeEnum.DEVICE_TYPE_INVALID);
            }

            try {
                // LoginUser userInfo = JwtUtils.getClientUserInfo(token);
                LoginUser userInfo = getTokenService().parse(token);
                userInfo.setDevice(deviceEnum.getDeviceType());  // 设备类型
                // 设置当前这个session的属性，后续我们在发送消息时，可以通过 session.getAttributes().get("clientUserInfo")可以取出 clientUserInfo参数
                attributes.put(WebSocketConstants.WS_USER_INFO_KEY, userInfo);
            } catch (Exception e) {
                log.error("webSocket 请求 token:{} ", token);
                log.error("webSocket 请求 device:{} ", device);
                log.error("webSocket 连接失败 ", e);
                return false;
            }
            return true;
        }

        return false;
    }

    /**
     * 建立请求之后
     *
     * @param request   the current request
     * @param response  the current response
     * @param wsHandler the target WebSocket handler
     * @param exception an exception raised during the handshake, or {@code null} if none
     */
    @Override
    public void afterHandshake(ServerHttpRequest request,
                               ServerHttpResponse response,
                               WebSocketHandler wsHandler,
                               Exception exception) {

    }


    // DCL 模式获取 tokenService 单例
    private TokenService getTokenService() {
        if (null == tokenService) {
            synchronized (TokenService.class) {
                if (null == tokenService) {
                    tokenService = ApplicationContextUtil.getBean(TokenService.class);
                }
            }
        }

        return tokenService;
    }

}
